package com.smh.demo1.a33;

import org.springframework.boot.SpringApplication;
import org.springframework.boot.WebApplicationType;
import org.springframework.boot.web.embedded.tomcat.TomcatServletWebServerFactory;
import org.springframework.context.ApplicationContextInitializer;
import org.springframework.context.ConfigurableApplicationContext;
import org.springframework.context.annotation.Bean;
import org.springframework.context.support.GenericApplicationContext;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Set;

/**
 * @author shiminghui
 * @date 2025/5/6 18:46
 * @description: TODO
 */
public class A33_1 {
    public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
        // 模拟springboot的启动流程

        SpringApplication springApplication = new SpringApplication(A33_1.class);
        // 1. 获取bean的定义源
        System.out.println("1. 获取bean的定义源");
        springApplication.setSources(Set.of("classpath:Bean1.xml"));

        // 2. 推断应用类型
        System.out.println("2. 推断应用类型");
        Method deduceFromClasspath = WebApplicationType.class.getDeclaredMethod("deduceFromClasspath");
        deduceFromClasspath.setAccessible(true);
        System.out.println("\t 应用类型为: " + deduceFromClasspath.invoke(null));
        // 3. ApplicationContextInitializer
        System.out.println("3. ApplicationContextInitializer");
        springApplication.addInitializers(new ApplicationContextInitializer<ConfigurableApplicationContext>() {
            @Override
            public void initialize(ConfigurableApplicationContext applicationContext) {
                if (applicationContext instanceof GenericApplicationContext gac) {
                    gac.registerBean("bean2", Bean2.class);
                }
            }
        });

        // 4. 监听器与事件
        System.out.println("4. 监听器与事件");
        springApplication.addListeners(event -> {
            System.out.println("\t监听到事件: " + event);
        });

        // 5. 主类推断
        System.out.println("5. 主类推断");
        Method deduceMainApplicationClass = SpringApplication.class.getDeclaredMethod("deduceMainApplicationClass");
        deduceMainApplicationClass.setAccessible(true);
        Object invoke = deduceMainApplicationClass.invoke(springApplication);
        System.out.println(invoke);

        // run方法内部会创建spring容器
        ConfigurableApplicationContext context = springApplication.run(args);

        System.out.println("-------------------------");
        // 打印一下bean
        String[] beanDefinitionNames = context.getBeanDefinitionNames();
        for (String beanDefinitionName : beanDefinitionNames) {
            System.out.println(beanDefinitionName);
        }

        context.close();
    }


    @Bean
    public TomcatServletWebServerFactory tomcatServletWebServerFactory() {
        return new TomcatServletWebServerFactory();
    }
}
